﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PROJECT_BOMBER.BLL
{
    public class AnimationSprite : ICloneable
    {
        public Point Position;
        protected Game Game;
        public AnimationDefinition Definition;
        protected SpriteBatch spriteBatch;
        public Texture2D Sprite;
        public Point CurrentFrame;
        protected bool FinishedAnimation = false;
        private float rotation;
        public Vector2 CenterRotation;

        /// <summary>
        /// Gets or sets the animation's rotation.
        /// </summary>
        /// <value>
        /// The animation's rotation.
        /// </value>
        protected float Rotation
        {
            get { return rotation; }
            set { rotation = value; }
        }

        protected double TimeBetweenFrame = 16; // 60 fps 

        protected double lastFrameUpdatedTime = 0;

        private int _Frameratebase = 60;
        /// <summary>
        /// Gets the framerate base.
        /// </summary>
        public int Frameratebase
        {
            get { return _Frameratebase; }
            private set { _Frameratebase = value; }
        }

        private int _Framerate = 60;
        /// <summary>
        /// Gets or sets the framerate.
        /// </summary>
        /// <value>
        /// The framerate.
        /// </value>
        public int Framerate
        {
            get { return this._Framerate; }
            set
            {
                if (value <= 0)
                    throw new ArgumentOutOfRangeException("Framerate can't be less or equal to 0");
                if (this._Framerate != value)
                {
                    this._Framerate = value;
                    this.TimeBetweenFrame = 1000.0d / (double)this._Framerate;
                }
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AnimationSprite"/> class.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <param name="definition">The animation's definition.</param>
        public AnimationSprite(Game game, AnimationDefinition definition)
        {
            this.Game = game;
            this.Definition = definition;
            this.Position = new Point();
            this.CurrentFrame = new Point();
        }

        /// <summary>
        /// Initializes the animation sprite
        /// </summary>
        public void Initialize()
        {
            this.Framerate = this.Definition.FrameRate;
            this.Frameratebase = this.Definition.FrameRate;
        }

        /// <summary>
        /// Loads the picture
        /// </summary>
        /// <param name="spritebatch">The spritebatch.</param>
        public void LoadContent(SpriteBatch spritebatch = null)
        {
            this.Sprite = this.Game.Content.Load<Texture2D>(Definition.AssetName);
            if (spritebatch == null)
                this.spriteBatch = new SpriteBatch(this.Game.GraphicsDevice);
            else
                this.spriteBatch = spritebatch;
        }

        /// <summary>
        /// Resets the animation
        /// </summary>
        public void Reset()
        {
            this.CurrentFrame = new Point();
            this.FinishedAnimation = false;
            this.lastFrameUpdatedTime = 0;
        }

        /// <summary>
        /// Updates the animation
        /// </summary>
        /// <param name="time">The time.</param>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="speed">The speed.</param>
        /// <param name="speedmax">The speedmax.</param>
        /// <param name="verif">if set to <c>true</c> [verif].</param>
        public void Update(int x, int y)
        {
            this.Position = new Point(x, y);

            Framerate = (int)(Frameratebase);


            if (FinishedAnimation) return;

            this.lastFrameUpdatedTime += Globals.GameTime.ElapsedGameTime.Milliseconds;
            if (this.lastFrameUpdatedTime > this.TimeBetweenFrame)
            {
                this.lastFrameUpdatedTime = 0;
                if (this.Definition.Loop)
                {
                    this.CurrentFrame.X++;
                    if (this.CurrentFrame.X >= this.Definition.NbFrames.X)
                    {
                        this.CurrentFrame.X = 0;
                        this.CurrentFrame.Y++;
                        if (this.CurrentFrame.Y >= this.Definition.NbFrames.Y)
                            this.CurrentFrame.Y = 0;
                    }
                }
                else
                {
                    this.CurrentFrame.X++;
                    if (this.CurrentFrame.X >= this.Definition.NbFrames.X)
                    {
                        this.CurrentFrame.X = 0;
                        this.CurrentFrame.Y++;
                        if (this.CurrentFrame.Y >= this.Definition.NbFrames.Y)
                        {
                            this.CurrentFrame.X = this.Definition.NbFrames.X - 1;
                            this.CurrentFrame.Y = this.Definition.NbFrames.Y - 1;
                            this.FinishedAnimation = true;
                        }
                    }
                }
            }
        }

        public void Update(int x, int y, Vector2 speed, int speedmax, bool verif)
        {
            this.Position = new Point(x, y);

            if (verif)
            {
                if (speed.X >= 0)
                {
                    Framerate = (int)(Frameratebase * (speed.X / speedmax)) + 1;
                }
                else
                {
                    Framerate = (int)(Frameratebase * (-speed.X / speedmax)) + 1;
                }
            }
            else
            {
                Framerate = (int)(Frameratebase);
            }

            if (FinishedAnimation) return;

            this.lastFrameUpdatedTime += Globals.GameTime.ElapsedGameTime.Milliseconds;
            if (this.lastFrameUpdatedTime > this.TimeBetweenFrame)
            {
                this.lastFrameUpdatedTime = 0;
                if (this.Definition.Loop)
                {
                    this.CurrentFrame.X++;
                    if (this.CurrentFrame.X >= this.Definition.NbFrames.X)
                    {
                        this.CurrentFrame.X = 0;
                        this.CurrentFrame.Y++;
                        if (this.CurrentFrame.Y >= this.Definition.NbFrames.Y)
                            this.CurrentFrame.Y = 0;
                    }
                }
                else
                {
                    this.CurrentFrame.X++;
                    if (this.CurrentFrame.X >= this.Definition.NbFrames.X)
                    {
                        this.CurrentFrame.X = 0;
                        this.CurrentFrame.Y++;
                        if (this.CurrentFrame.Y >= this.Definition.NbFrames.Y)
                        {
                            this.CurrentFrame.X = this.Definition.NbFrames.X - 1;
                            this.CurrentFrame.Y = this.Definition.NbFrames.Y - 1;
                            this.FinishedAnimation = true;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Updates the animation including the rotation.
        /// </summary>
        /// <param name="time">The time.</param>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="speed">The speed.</param>
        /// <param name="speedmax">The speedmax.</param>
        /// <param name="verif">if set to <c>true</c> [verif].</param>
        /// <param name="rot">The rotation.</param>
        /// <param name="center">The center.</param>
        public void Update(int x, int y, Vector2 speed, int speedmax, bool verif, float rot, Vector2 center)
        {
            this.Position = new Point(x, y);

            Rotation = rot;
            CenterRotation = center;

            if (verif)
            {
                if (speed.X >= 0)
                {
                    Framerate = (int)(Frameratebase * (speed.X / speedmax)) + 1;
                }
                else
                {
                    Framerate = (int)(Frameratebase * (-speed.X / speedmax)) + 1;
                }
            }
            else
            {
                Framerate = (int)(Frameratebase);
            }

            if (FinishedAnimation) return;

            this.lastFrameUpdatedTime += Globals.GameTime.ElapsedGameTime.Milliseconds;
            if (this.lastFrameUpdatedTime > this.TimeBetweenFrame)
            {
                this.lastFrameUpdatedTime = 0;
                if (this.Definition.Loop)
                {
                    this.CurrentFrame.X++;
                    if (this.CurrentFrame.X >= this.Definition.NbFrames.X)
                    {
                        this.CurrentFrame.X = 0;
                        this.CurrentFrame.Y++;
                        if (this.CurrentFrame.Y >= this.Definition.NbFrames.Y)
                            this.CurrentFrame.Y = 0;
                    }
                }
                else
                {
                    this.CurrentFrame.X++;
                    if (this.CurrentFrame.X >= this.Definition.NbFrames.X)
                    {
                        this.CurrentFrame.X = 0;
                        this.CurrentFrame.Y++;
                        if (this.CurrentFrame.Y >= this.Definition.NbFrames.Y)
                        {
                            this.CurrentFrame.X = this.Definition.NbFrames.X - 1;
                            this.CurrentFrame.Y = this.Definition.NbFrames.Y - 1;
                            this.FinishedAnimation = true;
                        }
                    }
                }
            }
        }

        public void Draw(bool DoBeginEnd = true)
        {
            //if (DoBeginEnd) this.spriteBatch.Begin();

            this.spriteBatch.Draw
                                ( 
                                      this.Sprite,
                                      new Rectangle(this.Position.X, this.Position.Y, this.Definition.FrameSize.X, this.Definition.FrameSize.Y),
                                      new Rectangle(this.CurrentFrame.X * this.Definition.FrameSize.X, this.CurrentFrame.Y * this.Definition.FrameSize.Y, this.Definition.FrameSize.X, this.Definition.FrameSize.Y),
                                      Color.White,
                                      Rotation,
                                      CenterRotation,
                                      SpriteEffects.None,
                                      1
                                );

            //if (DoBeginEnd) this.spriteBatch.End();
        }

        public object Clone()
        {
            AnimationSprite sprite = new AnimationSprite(this.Game, this.Definition);

            return sprite;
        }
    }
}
